#pragma once
#include <string>
#include <aio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctime>
#include <cstring>
#include <cstdarg>
#include <fstream>
#include "LockGuard.hpp"

enum
{
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
const std::string LOGFILE = ".log.txt";

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARNING:
        return "WARNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return "NONE";
    }
}
std::string GetCurrTime()
{
    time_t now = time(nullptr);
    struct tm *curr_time = localtime(&now);
    char buffer[128];
    snprintf(buffer, sizeof(buffer), "%d-%02d-%02d %02d:%02d:%02d",
             curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday,
             curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);
    return buffer;
}

class logmessage
{
public:
    std::string _level;
    pid_t _id;
    std::string _filename;
    int _filenumber;
    std::string _curr_time;
    std::string _message_info;
};

#define SCREEN_TYPE 1
#define FILE_TYPE 2
class Log
{
private:
    //向屏幕打印日志
    void FlushLogToScreen(const logmessage &lg)
    {
        printf("[%s][%d][%s][%d][%s] %s",
               lg._level.c_str(),
               lg._id,
               lg._filename.c_str(),
               lg._filenumber,
               lg._curr_time.c_str(),
               lg._message_info.c_str());
    }
    //向文件写入日志
    void FlushLogToFile(const logmessage &lg)
    {
        std::ofstream out(_logfile, std::ofstream::app);
        if (!out.is_open())
            return;
        char logtxt[2048];
        snprintf(logtxt, sizeof(logtxt), "[%s][%d][%s][%d][%s] %s",
                 lg._level.c_str(),
                 lg._id,
                 lg._filename.c_str(),
                 lg._filenumber,
                 lg._curr_time.c_str(),
                 lg._message_info.c_str());
        out.write(logtxt, sizeof(logtxt));
        out.flush();
        out.close();
    }
    void FlushLog(const logmessage &lg)
    {
        LockGuard guard(&gmutex); // 创建锁保护变量
        switch (_type)
        {
        case SCREEN_TYPE:
            FlushLogToScreen(lg);
            break;
        case FILE_TYPE:
            FlushLogToFile(lg);
            break;
        }
        // 函数结束自动销毁变量，释放锁
    }

public:
    Log(const std::string &logfile = LOGFILE) : _logfile(logfile), _type(SCREEN_TYPE)
    {
    }
    void Enable(int type)
    {
        _type = type;
    }
    void logMessage(std::string filename, int filenumber, int level, const char *format, ...)
    {
        logmessage lg;

        lg._level = LevelToString(level);
        lg._filename = filename;
        lg._filenumber = filenumber;
        lg._id = getpid();
        lg._curr_time = GetCurrTime();

        // 处理参数包
        va_list ap;
        va_start(ap, format);
        char log_info[1024];
        vsnprintf(log_info, sizeof(log_info), format, ap);
        va_end(ap);

        lg._message_info = log_info;

        FlushLog(lg);
    }
    ~Log()
    {
    }

private:
    int _type;                  // 存储日志类型
    const std::string _logfile; // 存储日志文件路径
};

Log lg;
#define LOG(level, format, ...)  do{lg.logMessage(__FILE__, __LINE__, level, format,##__VA_ARGS__);} while (0)